/**
 *       Copyright (c) 2012 Lukas Zaruba
 *
 *   This file is part of Robot Playground.
 *
 *   Robot Playground is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Robot Playground is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with Robot Playground. If not, see <http://www.gnu.org/licenses/>.
 */
package net.zarubsys.robotplayground.dummydevice.monitors;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;

import net.zarubsys.robotplayground.core.Environment;
import net.zarubsys.robotplayground.core.device.IDevice;
import net.zarubsys.robotplayground.core.modules.IModule;
import net.zarubsys.robotplayground.core.modules.IModuleConfiguration;
import net.zarubsys.robotplayground.core.modules.INotificationCause;
import net.zarubsys.robotplayground.core.monitors.IMonitor;
import net.zarubsys.robotplayground.core.monitors.IMonitorListener;
import net.zarubsys.robotplayground.dummydevice.modules.DummyMotionModule;
import net.zarubsys.robotplayground.dummydevice.modules.DummyTelemetryModule;
import net.zarubsys.robotplayground.dummydevice.modules.obstacles.DummyObstaclesModule;
import net.zarubsys.robotplayground.dummydevice.modules.obstacles.MapContainer;

/**
 * DummyPositionMonitor
 *
 * @author Lukas Zaruba, lukas.zaruba@gmail.com
 */
public class DummyPositionMonitor implements IMonitor {
	
	public static final String ID = "dummyPositionMonitor";
	
	private DummyTelemetryModule telemetry;
	private DummyMotionModule motion;
	private DummyObstaclesModule obstacles;
	
	private Environment env;
	private List<IMonitorListener> listeners;
	
	int lastX;
	int lastY;
	int lastDirection;

	@Override
	public void init(List<IModule<? extends IDevice, ? extends IModuleConfiguration>> modules, Environment env) {
		telemetry = (DummyTelemetryModule) modules.get(0);
		motion = (DummyMotionModule) modules.get(1);
		obstacles = (DummyObstaclesModule) modules.get(2);
		this.env = env;
	}

	@Override
	public void notify(IModule<?, ?> module, INotificationCause cause) {
		if (module != motion) return;
		
		Integer x = telemetry.getX();
		Integer y = telemetry.getY();
		Integer direction = telemetry.getDirection();
		
		if (x == lastX && y == lastY && direction == lastDirection) return;
		
		raiseEventToMonitorListeners(cause, x, y, direction);
		checkForEdge(x, y);
		checkForObstacle(x, y);
		updateLastPositions(x, y, direction);
	}

	private void updateLastPositions(Integer x, Integer y, Integer direction) {
		lastX = x;
		lastY = y;
		lastDirection = direction;
	}

	private void raiseEventToMonitorListeners(INotificationCause cause, Integer x, Integer y, Integer direction) {
		DummyPostionMonitorEventData eventData = new DummyPostionMonitorEventData(x, y, direction, lastX, lastY, lastDirection);
		notifyListenersInternal(eventData);
		tellPosition(cause);
	}

	private void checkForObstacle(Integer x, Integer y) {
		if (obstacles.isOnTheObstacle(x, y)) {
			String m = "Dummy device is on the obstacle! Terminating...";
			env.getLogger().error(m);
			env.stop(this, m);
		}
	}

	private void checkForEdge(Integer x, Integer y) {
		if (obstacles.isOnTheEdge(x, y)) {
			String m = "Dummy device is on the edge of the map! Terminating...";
			env.getLogger().error(m);
			env.stop(this, m);
		}
	}
	
	@SuppressWarnings("unchecked") // generics on this place make no sense
	private void notifyListenersInternal(DummyPostionMonitorEventData data) {
		if (listeners == null) return;
		for (IMonitorListener listener : listeners) {
			listener.notifyListener(data);
		}
	}
	
	private void tellPosition(INotificationCause cause) {
		Logger logger = env.getLogger();
		if (!logger.isDebugEnabled()) return;
		
		String message = "change - " + cause + ", postion: x=" + telemetry.getX() + ", y=" + telemetry.getY() + ", dir=" + telemetry.getDirection();
		logger.debug(message);
	}

	public int getX() {
		return telemetry.getX();
	}
	
	public int getY() {
		return telemetry.getY();
	}
	
	public int getDirection() {
		return telemetry.getDirection();
	}
	
	public MapContainer getMap() {
		return obstacles.getMap();
	}

	@Override
	public void registerMonitorListeners(List<IMonitorListener> listeners) {
		this.listeners = listeners;
	}

	@Override
	public String getId() {
		return ID;
	}

	@Override
	public List<String> getRequiredModules() {
		return new ArrayList<>(Arrays.asList(DummyTelemetryModule.ID, DummyMotionModule.ID, DummyObstaclesModule.ID));
	}

}

